package com.qiguliuxing.dts.admin.service;

import static com.qiguliuxing.dts.admin.support.AdminResponseCode.ORDER_CONFIRM_NOT_ALLOWED;

import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.qiguliuxing.dts.admin.support.AdminResponseCode;
import com.qiguliuxing.dts.db.bean.OrderVo;
import com.qiguliuxing.dts.db.bean.RefundOrderVo;
import com.qiguliuxing.dts.common.type.OrderStatusEnum;
import com.qiguliuxing.dts.common.type.RefundTypeEnum;
import com.qiguliuxing.dts.db.bean.UserVo;
import com.qiguliuxing.dts.db.domain.*;
import com.qiguliuxing.dts.service.base.*;
import com.qiguliuxing.dts.service.merchant.BillStatisService;
import com.qiguliuxing.dts.service.notify.NotifyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.pagehelper.PageInfo;
import com.qiguliuxing.dts.admin.support.AdminResponseUtils;
import com.qiguliuxing.dts.core.express.ExpressService;
import com.qiguliuxing.dts.core.notify.NotifyType;
import com.qiguliuxing.dts.core.support.JacksonUtil;
import com.qiguliuxing.dts.common.util.ResponseUtils;

@Service
public class AdminOrderService {
	private static final Logger logger = LoggerFactory.getLogger(AdminOrderService.class);

	@Autowired
	private DtsOrderGoodsService orderGoodsService;
	@Autowired
	private DtsOrderService orderService;
	@Autowired
	private DtsGoodsProductService productService;
	@Autowired
	private DtsUserService userService;
	@Autowired
	private DtsCommentService commentService;
	@Autowired
	private ExpressService expressService;
	@Autowired
	private DtsRefundService refundService;

	@Autowired
	private WxPayService wxPayService;

	@Autowired
	private NotifyService notifyService;

	@Autowired
	private AdminDataAuthService adminDataAuthService;

	@Autowired
	private DtsGrouponService grouponService;

	@Autowired
	private BillStatisService billStatisService;

	@Autowired
	private DtsTopicService dtsTopicService;

	public Object list(Integer userId, String orderSn,String startDate,String endDate,String mobile,Byte freightType,String fetchCode,Integer topicId,List<Short> orderStatusArray, Integer page, Integer limit,
			String sort, String order) {

		// 需要区分数据权限，如果属于品牌商管理员，则需要获取当前用户管理品牌店铺
		List<Integer> brandIds = null;
		if (adminDataAuthService.isBrandManager()) {
			brandIds = adminDataAuthService.getBrandIds();
			logger.info("运营商管理角色操作，需控制数据权限，brandIds:{}", JSONObject.toJSONString(brandIds));

			if (brandIds == null || brandIds.size() == 0) {//如果尚未管理任何入驻店铺，则返回空数据
				Map<String, Object> data = new HashMap<>();
				data.put("total", 0L);
				data.put("items", null);

				return ResponseUtils.ok(data);
			}
		}
		List<DtsOrder> orderList = null;
		orderList = orderService.querySelective(userId, orderSn,startDate,endDate,mobile,freightType,fetchCode,topicId,orderStatusArray, page, limit, sort,order);
		//验证订单是否可以存在退货子订单和团购类型订单（只有已购买等到发货的商品才验证是否团购中)
		List<OrderVo> orderVoList = null;
		long total = 0L;
		total = PageInfo.of(orderList).getTotal();
		if(orderList!=null){
			for (int i=0;i<orderList.size();i++){
				if(null!=orderList.get(i).getId()){
					List<DtsOrderGoods> dtsOrderGoods = orderGoodsService.queryByOid(orderList.get(i).getId());
					if (dtsOrderGoods.size()==0) {
					 orderList.remove(i);
					 total=total-1;
					}
				}
			}
		}
		if (orderList != null && orderList.size() > 0) {
			orderVoList = new ArrayList<OrderVo>();
			for (DtsOrder dtsOrder : orderList) {
				if(null!=dtsOrder.getId()){
					if(null!=dtsOrder.getTopicId()) {
						DtsTopic dtsTopic = dtsTopicService.findById(dtsOrder.getTopicId());
						if (null != dtsTopic && null != dtsTopic.getTitle()) {
							dtsOrder.setTopicName(dtsTopic.getTitle());
						}
					}
				}
				OrderVo orderVo = new OrderVo();
				BeanUtils.copyProperties(dtsOrder,orderVo);
				orderVo.setHasRefund(orderService.hasRefundByOrderId(dtsOrder.getId()));
				/**
				 * 已付款待发货的订单需要验证是否为团购订单，如果是团购订单还需要确认是团购已达到人数要求
				 */
				if (dtsOrder.getOrderStatus().intValue() == OrderStatusEnum.PAY.status.intValue()) {
					if(grouponService.isGrouponIng(dtsOrder.getId())){
						orderVo.setOrderStatus(OrderStatusEnum.GROUPON_ING.status);
					}
				}
				/**
				 * 自提订单查询是否有带上自提码进行查询，如果有则显示自提码
				 * 如果是店铺管理员发起查询，且条件未带上取货码，则不出现提货码在订单数据中
				 * fetchCode
				 */
				if (adminDataAuthService.isBrandManager() && StringUtils.isEmpty(fetchCode)) {
					logger.info("运营商管理角色操作，需控制数据权限，这里不给前端反馈取货码");
					orderVo.setFetchCode(null);//店铺管理员去掉取货码信息
				}

				orderVoList.add(orderVo);
			}
		}

		Map<String, Object> data = new HashMap<>();
		data.put("total", total);
		data.put("items", orderVoList);

		return ResponseUtils.ok(data);
	}

	public Object detail(Integer id) {
		DtsOrder order = orderService.findById(id);
		if (adminDataAuthService.isBrandManager()) {
			logger.info("运营商管理角色操作，需控制数据权限，这里不给前端反馈取货码");
			order.setFetchCode(null);//店铺管理员去掉取货码信息
		}
		List<DtsOrderGoods> orderGoods = orderGoodsService.queryByOid(id);
		UserVo user = userService.findUserVoById(order.getUserId());
		Map<String, Object> data = new HashMap<>();

		/**
		 * 已付款待发货的订单需要验证是否为团购订单，如果是团购订单还需要确认团购已达到人数要求
		 */
		if (order.getOrderStatus().intValue() == OrderStatusEnum.PAY.status.intValue()) {
			if(grouponService.isGrouponIng(order.getId())){
				order.setOrderStatus(OrderStatusEnum.GROUPON_ING.status);
			}
		}
		data.put("order", order);
		data.put("orderGoods", orderGoods);
		data.put("user", user);

		return ResponseUtils.ok(data);
	}

	/**
	 * 订单退款
	 * <p>
	 * 1. 检测当前订单是否能够退款; 2. 微信退款操作; 3. 设置订单退款确认状态； 4. 订单商品库存回库。
	 * <p>
	 * TODO 虽然接入了微信退款API，但是从安全角度考虑，建议开发者删除这里微信退款代码，采用以下两步走步骤： 1.
	 * 管理员登录微信官方支付平台点击退款操作进行退款 2. 管理员登录Dts管理后台点击退款操作进行订单状态修改和商品库存回库
	 *
	 * @param body 订单信息，{ orderId：xxx }
	 * @return 订单退款操作结果
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
	public Object refund(String body) {
		Integer refundId = JacksonUtil.parseInteger(body, "id");
		Integer orderId = JacksonUtil.parseInteger(body, "orderId");
		String refundAmount = JacksonUtil.parseString(body, "refundAmount");
		String approveMsg = JacksonUtil.parseString(body, "approveMsg");
		Byte approveStatus = JacksonUtil.parseByte(body, "approveStatus");
		if (refundId == null) {
			return ResponseUtils.badArgument();
		}
		if (StringUtils.isEmpty(refundAmount)) {
			return ResponseUtils.badArgument();
		}
		if (approveStatus == null || approveMsg == null){
			return ResponseUtils.badArgument();
		}
		DtsOrder order = orderService.findById(orderId);
		if (order == null) {
			return ResponseUtils.badArgument();
		}

		if (approveStatus.intValue() == RefundTypeEnum.APPROVE_REJECT.getStatus().intValue()) {
			DtsRefundTrace dtsRefundTrace = refundService.findRefundTraceById(refundId);
			if(null!=dtsRefundTrace) {
				if(null!=dtsRefundTrace.getOrderStatus()) {
					order.setOrderStatus(dtsRefundTrace.getOrderStatus());
					orderService.updateWithOptimisticLocker(order);
					refundService.deleteRefundById(refundId);
				}
			}
			List<DtsOrderGoods> dtsOrderGoods = orderGoodsService.queryByOid(orderId);
			for (DtsOrderGoods dtsOrderGood:dtsOrderGoods) {
				dtsOrderGood.setRefundId(-1);
				orderGoodsService.updateById(dtsOrderGood);
			}
			return ResponseUtils.ok();
		}
		/*if (order.getActualPrice().compareTo(new BigDecimal(refundMoney)) != 0) {
			return ResponseUtil.badArgumentValue();
		}

		// 如果订单不是退款状态，则不能退款
		if (!order.getOrderStatus().equals(OrderUtil.STATUS_REFUND)) {
			logger.info("商场管理->订单管理->订单退款失败:{}", ORDER_REFUND_FAILED.desc());
			return AdminResponseUtil.fail(ORDER_REFUND_FAILED);
		}*/

		// 退款金额不能超过订单付款金额
//		if (order.getActualPrice().compareTo(new BigDecimal(refundAmount)) < 0) {
//			return AdminResponseUtils.fail(AdminResponseCode.REFUND_AMOUNT_BEYOND);
//		}

		/**
		 * add by qiguliuxing 2020-12-03
		 * 增加条件，商户的退款金额不能大于可提现金额
		 * 因为商户提现是T+1模式，未避免平台垫付资金引起风险，商户操作退款时，必须保证商户可提现资金大于退款金额
		 */
		Integer brandId = orderGoodsService.getBrandId(orderId);
		BigDecimal withdrawableAmount = billStatisService.getWithdrawableAmount(brandId);
	/*	if (withdrawableAmount.compareTo(new BigDecimal(refundAmount)) < 0) {
			return AdminResponseUtils.fail(AdminResponseCode.NO_AVAILABLE_AMOUNT);
		}*/

		/**
		 * 退款审批通过，则做微信退款
		 * 温馨提示：这里可以屏蔽api接口，系统平台仅做订单状态的更新和信息提醒，实际退款可到微信商户端，根据支付订单进行退款
		 * 这里的接口调用依赖商户证书
 		 */
		if (approveStatus.intValue() == RefundTypeEnum.APPROVE_FINISH.getStatus().intValue()) {
			WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
			String orderSn=order.getOrderSn();
			Integer totalFee=order.getActualPrice().multiply(new BigDecimal(100)).intValue();
			if(order.getOrderSn().contains("_")){
				String[] split = order.getOrderSn().split("_");
				orderSn=split[0];
			/*	List<DtsOrder> dtsOrders = orderService.findListBySns(orderSn);
				for (DtsOrder dtsOrder: dtsOrders) {
					totalFee=totalFee+dtsOrder.getActualPrice().multiply(new BigDecimal(100)).intValue();
				}*/
				DtsOrder bySns = orderService.findBySns(orderSn);
				totalFee=bySns.getActualPrice().multiply(new BigDecimal(100)).intValue();
			}
			System.out.println("orderSn ====================== " + orderSn);
			wxPayRefundRequest.setOutTradeNo(orderSn);
			wxPayRefundRequest.setOutRefundNo("refund_" +orderSn);
			// 元转成分
			wxPayRefundRequest.setTotalFee(totalFee);
			Integer refundFree = new BigDecimal(refundAmount).multiply(new BigDecimal(100)).intValue();
			wxPayRefundRequest.setRefundFee(refundFree);
			System.out.println("wxPayRefundRequest = " + wxPayRefundRequest);
			WxPayRefundResult wxPayRefundResult;
			try {
				wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
			} catch (WxPayException e) {
				logger.error(e.getMessage(), e);
				return AdminResponseUtils.fail(AdminResponseCode.ORDER_REFUND_OP_FAILED);
			}
			if (!"SUCCESS".equals(wxPayRefundResult.getReturnCode())) {
				logger.warn("警告，退款失败: " + wxPayRefundResult.getReturnMsg());
				return AdminResponseUtils.fail(AdminResponseCode.ORDER_REFUND_OP_FAILED);
			}
			if (!"SUCCESS".equals(wxPayRefundResult.getResultCode())) {
				logger.warn("警告，退款失败: " + wxPayRefundResult.getReturnMsg());
				return AdminResponseUtils.fail(AdminResponseCode.ORDER_REFUND_OP_FAILED);
			}
		}

		//退货跟踪表数据状态调整为已退款
		refundService.approveRefund(refundId,approveStatus,approveMsg,refundAmount);

        // 退款通过，则商品货品数量增加
		if (approveStatus.intValue() == RefundTypeEnum.APPROVE_FINISH.getStatus().intValue()) {
			List<DtsOrderGoods> orderGoodsList = refundService.queryOrderGoodsByRefundId(refundId);
			for (DtsOrderGoods orderGoods : orderGoodsList) {
				Integer productId = orderGoods.getProductId();
				Short number = orderGoods.getNumber();
				if (productService.addStock(productId, number) == 0) {
					logger.info("商场管理->订单管理->订单退款失败:{}", "商品货品库存增加失败");
					throw new RuntimeException("商品货品库存增加失败");
				}
			}
		}

		if (order.getOrderStatus().intValue() == OrderStatusEnum.REFUND.status.intValue()) {//如果订单是已退款中，表示所有商品都已经退款中，则如果所有的退款子订单都已经完成退款，需调整状态
			Long unFinishCnt = refundService.unFinishCntRefundByOrderId(orderId,RefundTypeEnum.APPROVE_FINISH.getStatus());
			if (unFinishCnt == 0){ //没完成的退款子订单数已经为 0 即所有子退款订单已经完成，设置订单取消状态
				order.setOrderStatus(OrderStatusEnum.REFUND_CONFIRM.status);
				if (orderService.updateWithOptimisticLocker(order) == 0) {
					logger.info("商场管理->订单管理->订单退款失败:{}", "更新数据已失效");
					throw new RuntimeException("更新数据已失效");
				}
			}
		}

		// TODO 发送邮件和短信通知，这里采用异步发送
		// 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
		// 注意订单号只发后6位
		if (approveStatus.intValue() == RefundTypeEnum.APPROVE_FINISH.getStatus().intValue()) {
			notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND,
					new String[] { order.getOrderSn().substring(8, 14) });
		}
		return ResponseUtils.ok();
	}

	/**
	 * 发货 1. 检测当前订单是否能够发货 2. 设置订单发货状态
	 *
	 * @param body 订单信息，{ orderId：xxx, shipSn: xxx, shipChannel: xxx }
	 * @return 订单操作结果 成功则 { errno: 0, errmsg: '成功' } 失败则 { errno: XXX, errmsg: XXX }
	 */
	public Object ship(String body) {
		Integer orderId = JacksonUtil.parseInteger(body, "orderId");
		String shipSn = JacksonUtil.parseString(body, "shipSn");
		String shipChannel = JacksonUtil.parseString(body, "shipChannel");
		Integer returnAddressId = JacksonUtil.parseInteger(body, "returnAddressId");
		if (orderId == null || shipSn == null || shipChannel == null) {
			return ResponseUtils.badArgument();
		}

		DtsOrder order = orderService.findById(orderId);
		if (order == null) {
			return ResponseUtils.badArgument();
		}

		// 如果订单不是已付款状态，则不能发货
		if (!order.getOrderStatus().equals(OrderStatusEnum.PAY.status)) {
			logger.info("商场管理->订单管理->订单发货失败:{}", ORDER_CONFIRM_NOT_ALLOWED.desc());
			return AdminResponseUtils.fail(ORDER_CONFIRM_NOT_ALLOWED);
		}

		order.setOrderStatus(OrderStatusEnum.SHIP.status);
		order.setShipSn(shipSn);
		order.setReturnAddressId(returnAddressId);
		order.setShipChannel(shipChannel);
		order.setShipTime(LocalDateTime.now());
		if (orderService.updateWithOptimisticLocker(order) == 0) {
			logger.info("商场管理->订单管理->订单发货失败:{}", "更新数据失败!");
			return ResponseUtils.updatedDateExpired();
		}

		// TODO 发送邮件和短信通知，这里采用异步发送
		// 发货会发送通知短信给用户: *
		// "您的订单已经发货，快递公司 {1}，快递单 {2} ，请注意查收"
		notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[] { shipChannel, shipSn });

		return ResponseUtils.ok();
	}

	/**
	 * 回复订单商品
	 */
	public Object reply(Integer adminId,String body) {
		Integer commentId = JacksonUtil.parseInteger(body, "commentId");
		if (commentId == null || commentId == 0) {
			return ResponseUtils.badArgument();
		}
		/*if (commentService.findById(commentId) != null) {
			logger.info("商场管理->订单管理->订单商品回复:{}", ORDER_REPLY_EXIST.desc());
			return AdminResponseUtil.fail(ORDER_REPLY_EXIST);
		}*/
		DtsComment oldComment = commentService.findById(commentId);
		String content = JacksonUtil.parseString(body, "content");
		if (StringUtils.isEmpty(content)) {
			return ResponseUtils.badArgument();
		}
		// 创建评价回复
		DtsComment comment = new DtsComment();
		comment.setType(oldComment.getType());
		comment.setValueId(oldComment.getValueId());
		comment.setContent(content);
		comment.setUserId(null);
		comment.setHasPicture(false); // 评价回复没有用
//		comment.setPicUrls(new String[] {}); // 评价回复没有用
		comment.setStar((short) 0); // 评价回复没有用
		comment.setAddTime(LocalDateTime.now());//创建时间
		comment.setUpdateTime(LocalDateTime.now());//更新时间
		comment.setRepliedToId(commentId);//回复的评论
		comment.setIsRoot(false);//非根评论
		comment.setRootId(oldComment.getRootId() != null && oldComment.getRootId().intValue() > 0 ? oldComment.getRootId() : oldComment.getId());
		comment.setAdminId(adminId);
		commentService.save(comment);

		return ResponseUtils.ok();
	}

	/**
	 * 快递公司列表
	 * @return
	 */
	public Object listShipChannel() {
		List<Map<String, String>> vendorMaps = expressService.getAllVendor();
		List<Map<String, Object>> shipChannelList = new ArrayList<Map<String, Object>>(vendorMaps == null ? 0 : vendorMaps.size());
		for (Map<String, String> map : vendorMaps) {
			Map<String, Object> b = new HashMap<>(2);
			b.put("value", map.get("code"));
			b.put("label", map.get("name"));
			shipChannelList.add(b);
		}

		Map<String, Object> data = new HashMap<>();
		data.put("shipChannelList", shipChannelList);
		logger.info("获取已配置的快递公司总数：{}",shipChannelList.size());
		return ResponseUtils.ok(data);
	}

	/**
	 * 提货确认（店铺管理员或用户均可对自提订单进行提货确认）
	 * @param body
	 * @return
	 */
	public Object confirm(String body) {
		Integer orderId = JacksonUtil.parseInteger(body, "orderId");
		if (orderId == null) {
			return ResponseUtils.badArgument();
		}
		DtsOrder order = orderService.findById(orderId);
		if (order == null) {
			return ResponseUtils.badArgument();
		}
		// 设置订单确认状态
		order.setOrderStatus(OrderStatusEnum.CONFIRM.status);
		//如果是自提订单，确认收货时需设置发货时间为自提确认时间
		if (order.getFreightType().intValue() == 1){
			order.setShipTime(LocalDateTime.now());
		}
		order.setConfirmTime(LocalDateTime.now());

		if (orderService.updateWithOptimisticLocker(order) == 0) {
			logger.info("商场管理->订单管理->订单提货确认失败:{}", "更新数据已失效");
			throw new RuntimeException("更新数据已失效");
		}

		return ResponseUtils.ok();
	}

	/**
	 * 根据订单id获取子退货订单
	 * @param id
	 * @return
	 */
	public Object detailRefundOrder(Integer id) {
		DtsOrder order = orderService.findById(id);

		//获取每个退货子订单及每个子订单中的商品信息
		List<RefundOrderVo> refundOrderList = new ArrayList<RefundOrderVo>();
		List<DtsRefundTrace> refundTraceList = refundService.findRefundTraceByOrderId(id);
		for (DtsRefundTrace refundTrace : refundTraceList) {
			RefundOrderVo refundOrder = new RefundOrderVo();
			List<DtsOrderGoods> refundGoodsList = refundService.queryOrderGoodsByRefundId(refundTrace.getId());
			refundOrder.setRefundTrace(refundTrace);
			refundOrder.setRefundGoods(refundGoodsList);
			refundOrderList.add(refundOrder);
		}

		UserVo user = userService.findUserVoById(order.getUserId());
		Map<String, Object> data = new HashMap<>();
		data.put("order", order);
		data.put("refundOrderList", refundOrderList);
		data.put("user", user);

		return ResponseUtils.ok(data);
	}

	public Object getTopic(){
		List<DtsTopic> dtsTopics = dtsTopicService.queryList();
		List<Map<String, Object>> brandList = new ArrayList<>();
		for (DtsTopic dtsTopic: dtsTopics) {
			Map<String, Object> b = new HashMap<>(2);
			b.put("id", dtsTopic.getId());
			b.put("name", dtsTopic.getTitle());
			brandList.add(b);
		}
		return ResponseUtils.ok(brandList);
	}
}
